<!DOCTYPE html>
<head>
	<meta http-equiv="Content-type" content="text/html; charset=utf-8">
	<title>Integration with DHTMLX Suite</title>
	<script src="../../codebase/dhtmlxgantt.js?v=8.0.6"></script>
	<link rel="stylesheet" href="../../codebase/dhtmlxgantt.css?v=8.0.6">

	<script type="text/javascript" src="https://cdn.dhtmlx.com/suite/8.0/suite.js?v=8.0.6"></script>
	<script type="text/javascript" src="./common/suite_task_editor.js?v=8.0.6"></script>
	<script type="text/javascript" src="./common/suite_link_editor.js?v=8.0.6"></script>
	<script type="text/javascript" src="./common/suite_calendar_editor.js?v=8.0.6"></script>
	<script type="text/javascript" src="./common/suite_resource_editor.js?v=8.0.6"></script>
	<link rel="stylesheet" href="https://docs.dhtmlx.com/suite/codebase/suite.css?v=6.0.3">
	<link href="https://cdn.materialdesignicons.com/3.6.95/css/materialdesignicons.min.css?v=6.4.2" media="all" rel="stylesheet" type="text/css">
	<style>
		html, body {
			height: 100%;
			width:100%;
			padding: 0px;
			margin: 0px;
			/*overflow: hidden;*/
		}

		/*⇊⇊⇊resource section⇊⇊⇊*/
		.gantt_grid_scale .gantt_grid_head_cell,
		.gantt_task .gantt_task_scale .gantt_scale_cell {
			font-weight: bold;
			font-size: 14px;
			color: rgba(0, 0, 0, 0.7);
		}

		.resource_marker{
			text-align: center;
		}
		.resource_marker div{
			width: 15px;
			height: 14px;
			line-height: 14px;
			display: inline-block;
			border-radius: 3px;
			color: #FFF;
		}
		.resource_marker.workday_ok div {
			background: #51c185;
		}

		.resource_marker.workday_over div{
			background: #ff8686;
		}
		/*↑↑↑resource section↑↑↑*/


		.owner-label{
			width: 20px;
			height: 20px;
			line-height: 20px;
			font-size: 12px;
			display: inline-block;
			border: 1px solid #cccccc;
			border-radius: 25px;
			background: #e6e6e6;
			color: #6f6f6f;
			margin: 0 3px;
			font-weight: bold;
		}

		#calendarSelector, #calendarDatesEditor, #resourceEdit{
			display: flex;
		}
		#calendarSelector select, #resourceEdit select{
			width: 100%;
		}

		#slider_container{
			display: flex;
		}

		#slider{
			width: 150px;
		}

		#zoom_level{
			width: 70px;
		}



		.new_calendar_name{
			z-index: 999999999999;
		}
		.weekend{ 
			background: #f8f0ff;
		}



	</style>
</head>

<body>
<div id="slider_container" >
	<label id=zoom_level>Week &nbsp;</label>
	<div id="slider" ></div>
</div>
<div id="gantt_here" style='width:100%; height:90%'></div>
<script>
	// Gantt configuration
	var taskData = {
		"data": [
			{ "id": "10", "text": "Project #1", "start_date": "10-04-2025", "end_date": "14-04-2025", "order": 10, "progress": 0.4, "open": true, "tags": ['1', '3'] },
			{ "id": "1", "text": "Task #1", "owner": [{ "resource_id": "6", "value": "5" }, { "resource_id": "7", "value": "2" }], "start_date": "10-04-2025", "end_date": "13-04-2025", "order": 10, "progress": 0.6, "parent": "10", "tags": ['1'] },
			{ "id": "2", "text": "Task #2", "owner": [{ "resource_id": "8", "value": "3" }], "calendar_id": "fulltime", "start_date": "11-04-2025", "end_date": "14-04-2025", "order": 20, "progress": 0.6, "parent": "10", "description": "This task has its own calendars, so it will override resource calendar settings. Change the task calendar to global to apply resource calendars.", "tags": ['5'] },
			{ "id": "20", "text": "Project #2", "start_date": "10-04-2025", "duration": 24, "order": 10, "progress": 0.4, "type": "project", "open": true, "tags": ['2'] },
			{ "id": "3", "text": "Task #3", "owner": [{ "resource_id": "9", "value": "7" }], "calendar_id": "custom", "start_date": "12-04-2025", "end_date": "14-04-2025", "order": 10, "progress": 0.6, "parent": "20", "description": "This task has its own calendars, so it will override resource calendar settings. Change the task calendar to global to apply resource calendars." },
			{ "id": "4", "text": "Task #4", "owner": [{ "resource_id": "10", "value": "12" }, { "resource_id": "9", "value": "9" }], "start_date": "14-04-2025", "end_date": "16-04-2025", "order": 20, "progress": 0.6, "parent": "20", "tags": ['3', '4'] }
		],
		"links": [
			{ "id": "1", "source": '1', "target": '2', "type": "0" },
			{ "id": "2", "source": '2', "target": '3', "type": "0" },
			{ "id": "3", "source": '3', "target": '4', "type": "0" },
			{ "id": "4", "source": '2', "target": '5', "type": "0" }
		]
	}

	gantt.plugins({
		auto_scheduling: true
	});
	gantt.config.auto_scheduling = true;

	gantt.config.duration_unit = "hour"


	var zoomConfig = {
		levels: [
			{
				name: "hour",
				scale_height: 50,
				min_column_width: 15,
				scales: [
					{ unit: "day", format: "%d" },
					{ unit: "hour", format: "%H" },
				]
			},

			{
				name: "day",
				scale_height: 50,
				min_column_width: 80,
				scales: [
					{ unit: "day", step: 1, format: "%d %M" }
				]
			},
			{
				name: "week",
				scale_height: 50,
				min_column_width: 50,
				scales: [
					{
						unit: "week", step: 1, format: function (date) {
							var dateToStr = gantt.date.date_to_str("%d %M");
							var endDate = gantt.date.add(date, -6, "day");
							var weekNum = gantt.date.date_to_str("%W")(date);
							return "#" + weekNum + ", " + dateToStr(date) + " - " + dateToStr(endDate);
						}
					},
					{ unit: "day", step: 1, format: "%j %D" }
				]
			},
			{
				name: "month",
				scale_height: 50,
				min_column_width: 120,
				scales: [
					{ unit: "month", format: "%F, %Y" },
					{ unit: "week", format: "Week #%W" }
				]
			},
			{
				name: "quarter",
				height: 50,
				min_column_width: 90,
				scales: [
					{
						unit: "quarter", step: 1, format: function (date) {
							var dateToStr = gantt.date.date_to_str("%M");
							var endDate = gantt.date.add(gantt.date.add(date, 3, "month"), -1, "day");
							return dateToStr(date) + " - " + dateToStr(endDate);
						}
					},
					{ unit: "month", step: 1, format: "%M" },
				]
			},
			{
				name: "year",
				scale_height: 50,
				min_column_width: 30,
				scales: [
					{ unit: "year", step: 1, format: "%Y" }
				]
			}
		],
		useKey: "ctrlKey",
		trigger: "wheel",
		element: function () {
			return gantt.$root.querySelector(".gantt_task");
		}
	};

	gantt.ext.zoom.init(zoomConfig);
	gantt.ext.zoom.setLevel("week");
	gantt.config.bar_height = 20;

	gantt.config.work_time = true;
	// gantt.config.correct_work_time = true; 
	gantt.templates.timeline_cell_class = function (task, date) {
		if (!gantt.isWorkTime({ date: date, task: task, unit: gantt.getScale().unit })) return "weekend";
	};
	gantt.config.dynamic_resource_calendars = true;

	gantt.addCalendar({
		id: "custom"
	});
	gantt.getCalendar("custom").setWorkTime({ date: gantt.date.str_to_date("%d-%m-%Y")("10-04-2025"), hours: ["8:00-12:00"] })
	gantt.getCalendar("custom").setWorkTime({ date: gantt.date.str_to_date("%d-%m-%Y")("12-04-2025"), hours: ["9:00-18:00"] })
	gantt.getCalendar("custom").setWorkTime({ date: gantt.date.str_to_date("%d-%m-%Y")("14-04-2025"), hours: false })


	/*
		var autoFormatter = gantt.ext.formatters.durationFormatter({
			enter: "day",
			store: "hour",
			format: "auto"
		});
	*/
	gantt.config.columns = [
		{ name: "text", tree: true, width: 200, resize: true },
		{ name: "start_date", align: "center", width: 80, resize: true },
		{
			name: "owner", align: "center", width: 75, label: "Owner", template: function (task) {
				if (task.type == gantt.config.types.project) {
					return "";
				}

				var store = gantt.getDatastore("resource");
				var assignments = task[gantt.config.resource_property];

				if (!assignments || !assignments.length) {
					return "Unassigned";
				}

				if (assignments.length == 1) {
					var resourceItem = store.getItem(assignments[0].resource_id)
					if (!resourceItem) {
						return "Unassigned"
					}
					return store.getItem(assignments[0].resource_id).text;
				}

				var result = "";
				assignments.forEach(function (assignment) {
					var owner = store.getItem(assignment.resource_id);
					if (!owner) {
						return;
					}
					result += "<div class='owner-label' title='" + owner.text + "'>" + owner.text.substr(0, 1) + "</div>";

				});

				return result;
			}, resize: true
		},
		{
			name: "duration", label: "Duration", resize: true, align: "center", /*template: function(task) {
			return autoFormatter.format(task.duration);
		},*/width: 100
		},
		{ name: "add", width: 44 }
	];

	function getResourceAssignments(resourceId) {
		var assignments;
		var store = gantt.getDatastore(gantt.config.resource_store);
		var resource = store.getItem(resourceId);

		if (resource.$level === 0) {
			assignments = [];
			store.getChildren(resourceId).forEach(function (childId) {
				assignments = assignments.concat(gantt.getResourceAssignments(childId));
			});
		}
		else if (resource.$level === 1) {
			assignments = gantt.getResourceAssignments(resourceId);
		}
		else {
			assignments = gantt.getResourceAssignments(resource.$resource_id, resource.$task_id);
		}
		return assignments;
	}

	var resourceConfig = {
		columns: [
			{
				name: "name", label: "Name", tree: true, template: function (resource) {
					return resource.text;
				}
			},
			{
				name: "workload", label: "Workload", template: function (resource) {

					var totalDuration = 0;
					if (resource.$role === "task") {
						gantt.getResourceAssignments(resource.$resource_id, resource.$task_id).forEach(function (a) {
							totalDuration += a.value * a.duration;
						});
					} else {
						getResourceAssignments(resource.id).forEach(function (assignment) {
							totalDuration += Number(assignment.value) * assignment.duration;
						});
					}
					return (totalDuration || 0) + "h";

					/*	var totalDuration = 0;
							if (resource.$level == 2) {
									var assignment = gantt.getResourceAssignments(resource.$resource_id, resource.$task_id)[0];
									totalDuration = resource.duration * assignment.value;
							} else {
									var assignments = getResourceAssignments(resource.id);
									assignments.forEach(function (assignment) {
											var task = gantt.getTask(assignment.task_id);
											totalDuration += Number(assignment.value) * task.duration;
									});
							}

							return (totalDuration || 0) + "h";*/
				}
			}
		]
	};

	gantt.templates.resource_cell_class = function (start_date, end_date, resource, tasks) {
		var css = [];
		css.push("resource_marker");
		if (tasks.length <= 1) {
			css.push("workday_ok");
		} else {
			css.push("workday_over");
		}
		return css.join(" ");
	};

	gantt.templates.resource_cell_value = function (start_date, end_date, resource, tasks) {
		var result = 0;
		tasks.forEach(function (item) {
			var assignments = gantt.getResourceAssignments(resource.id, item.id);
			assignments.forEach(function (assignment) {
				var task = gantt.getTask(assignment.task_id);
				if (+assignment.start_date <= +start_date && +end_date <= +assignment.end_date) {
					result += assignment.value * 1;
				}
			});
		});

		if (result % 1) {
			result = Math.round(result * 10) / 10;
		}
		return "<div>" + result + "</div>";
	};

	gantt.config.resource_store = "resource";
	gantt.config.resource_property = "owner";
	gantt.config.order_branch = true;
	gantt.config.open_tree_initially = true;
	gantt.config.layout = {
		css: "gantt_container",
		rows: [
			{
				cols: [
					{ view: "grid", group: "grids", scrollY: "scrollVer" },
					{ resizer: true, width: 1 },
					{ view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer" },
					{ view: "scrollbar", id: "scrollVer", group: "vertical" }
				],
				gravity: 2
			},
			{ resizer: true, width: 1 },
			{
				config: resourceConfig,
				cols: [
					{ view: "resourceGrid", group: "grids", width: 435, scrollY: "resourceVScroll" },
					{ resizer: true, width: 1 },
					{ view: "resourceTimeline", scrollX: "scrollHor", scrollY: "resourceVScroll" },
					{ view: "scrollbar", id: "resourceVScroll", group: "vertical" }
				],
				gravity: 1
			},
			{ view: "scrollbar", id: "scrollHor" }
		]
	};

	gantt.$resourceStore = gantt.createDatastore({
		name: gantt.config.resource_store,
		type: "treeDatastore",
		initItem: function (item) {
			item.parent = item.parent || gantt.config.root_id;
			item[gantt.config.resource_property] = item.id;
			item.open = true;
			return item;
		}
	});

	gantt.$resourceStore.attachEvent("onFilterItem", function (id, item) {
		if (item.hide) {
			return false;
		}
		return true;
	});


	gantt.$resourceStore.attachEvent("onParse", function () {
		var people = [];
		gantt.$resourceStore.eachItem(function (res) {
			if (!gantt.$resourceStore.hasChild(res.id)) {
				var copy = gantt.copy(res);
				copy.key = res.id;
				copy.label = res.text;
				people.push(copy);
			}
		});
		gantt.updateCollection("people", people);
	});

	gantt.$resourceStore.parse([
		{ id: '1', text: "QA", parent: null },
		{ id: '2', text: "Development", parent: null },
		{ id: '3', text: "Sales", parent: null },
		{ id: '4', text: "Other", parent: null },
		{ id: '5', text: "Unassigned", parent: '4' },
		{ id: '6', text: "John", parent: '1', unit: "hours/day" },
		{ id: '7', text: "Mike", parent: '2', unit: "hours/day" },
		{ id: '8', text: "Anna", parent: '2', unit: "hours/day" },
		{ id: '9', text: "Bill", parent: '3', unit: "hours/day" },
		{ id: '10', text: "Floe", parent: '3', unit: "hours/day" }
	]);

	gantt.attachEvent("onBeforeTaskAdd", function (id, task) {
		// Suite expects String type for the IDs
		task.id += "";
		return true;
	});
	gantt.attachEvent("onBeforeLinkAdd", function (id, link) {
		// Suite expects String type for the IDs
		link.id += "";
		return true;
	});


	gantt.init("gantt_here");

	gantt.parse(taskData);



	// DHTMLX Components configuration

	var slider = new dhx.Slider("slider", {
		min: 0,
		max: 4,
		value: 2,
		// tooltip: true,
		step: 1
	});

	slider.events.on("Change", function (newValue, oldValue, isRange) {
		gantt.ext.zoom.setLevel(newValue);
		document.querySelector("#zoom_level").innerHTML = zoomConfig.levels[newValue].name.replace(/(^\w|\s\w)/g, function (m) { return m.toUpperCase() })
	});


	//Custom lightbox configuration
	var dhxWindow = new dhx.Window({
		title: "DHX Window",
		modal: false,
		resizable: true,
		movable: true,
		closable: true,
		header: true,
		footer: true,
		viewportOverflow: true,
		height: 500,
		width: 700,
		minWidth: 400,
		minHeight: 300
	});

	dhxWindow.footer.data.add({
		type: "button",
		view: "flat",
		size: "medium",
		color: "primary",
		value: "Save",
		id: "save",
	});
	dhxWindow.footer.data.add({
		type: "button",
		view: "link",
		size: "medium",
		color: "primary",
		value: "Cancel",
		id: "cancel",
	});
	dhxWindow.footer.data.add({
		type: "button",
		view: "link",
		size: "medium",
		color: "danger",
		value: "Delete",
		id: "delete",
	});


	dhxWindow.footer.events.on("click", function (id) {
		if (id === "save") {
			saveTask()
			dhxWindow.hide()
		}
		if (id === "cancel") {
			dhxWindow.hide()
		}
		if (id === "delete") {
			deleteTask()
			dhxWindow.hide()
		}
	});



	var formatDate = gantt.date.str_to_date("%Y-%m-%d");

	gantt.showLightbox = function (id) {
		dhxWindow.show();

		gantt._lightbox_id = id;
		var task = gantt.getTask(id);
		gantt._lightbox_task = gantt.copy(task);
		gantt._lightbox_links = "load";
		gantt._removed_links = [];


		var title = document.querySelector(".dhx_navbar-title")
		title.innerHTML = task.text || "New task"

		addTabBar()
}


	dhxWindow.handLightboxClick = function (e) {
		var tab = gantt._tabbar.getActive();
		var functionName = e.target.dataset.onclick;
		var functionArgument = e.target.dataset.onclick_argument;
		if (functionName) {
			gantt.$lightboxControl[tab][functionName](functionArgument);
		}
	}


	dhxWindow.events.on("AfterShow", function (position) {
		gantt.event(dhxWindow._popup, "click", dhxWindow.handLightboxClick);
	});
	dhxWindow.events.on("BeforeHide", function (position, events) {
		gantt.hideLightbox();
		gantt.eventRemove(dhxWindow._popup, "click", dhxWindow.handLightboxClick);
	});


	gantt.hideLightbox = function () {
		if (gantt._lightbox_task.$new) {
			deleteTask()
		}
		gantt._lightbox_task = null;
		gantt._lightbox_id = null;
	}


	function saveTask() {
		var id = gantt.getState().lightbox;

		var task = gantt.getTask(gantt._lightbox_id);

		// update task properties
		gantt.mixin(task, gantt._lightbox_task)

		if (task.$new) {
			delete gantt._lightbox_task.$new;
			delete task.$new;
			gantt.addTask(task)
		}
		else {
			gantt.updateTask(id)
		}

		//update resources
		var assignmentStore = gantt.getDatastore(gantt.config.resource_assignment_store);
		var assignments = gantt._lightbox_task[gantt.config.resource_property] || [];
		for (var i = 0; i < assignments.length; i++) {
			var updatedAssignment = assignments[i]
			var existingAssignmentId = updatedAssignment.$id;
			var existingAssignment = assignmentStore.getItem(existingAssignmentId)
			if (existingAssignment) {
				for (var property in updatedAssignment) {
					existingAssignment[property] = updatedAssignment[property]
				}
			}
			else {
				//assignmentStore.addItem(resource)
			}
		}

		for (var i = 0; i < gantt._removed_links.length; i++) {
			var linkId = gantt._removed_links[i];
			if (gantt.isLinkExists(linkId)) gantt.deleteLink(linkId)
		}

		var links = gantt._lightbox_links;
		if (links != "load") {
			for (var i = 0; i < links.length; i++) {
				var link = links[i];
				if (gantt.isLinkExists(link.id)) {
					var oldLink = gantt.getLink(link.id);
					oldLink.source = link.source;
					oldLink.target = link.target;
					oldLink.type = link.type;
					oldLink.lag = link.lag;
					gantt.updateLink(link.id);
				}
				else if (gantt.isTaskExists(link.source) && gantt.isTaskExists(link.target)) {
					gantt.addLink(link);
				}
			}
		}

	}
	function deleteTask() {
		var id = gantt.getState().lightbox;
		gantt.deleteTask(id)
	}


	function addTabBar() {
		if (gantt._tabbar) gantt._tabbar.destructor();

		gantt._tabbar = new dhx.Tabbar(null, {
			views: [
				{ id: "task", tab: "Task Data", css: "panel flex" },
				{ id: "links", tab: "Links", css: "panel flex" },
				{ id: "calendars", tab: "Calendars", css: "panel flex" },
				{ id: "resources", tab: "Resources", css: "panel flex" }
			]
		});
		dhxWindow.attach(gantt._tabbar)

		dhx.awaitRedraw().then(function () {
			gantt.$lightboxControl.fillTabContent()
		})


		gantt._tabbar.events.on("Change", function (activeId, prevId) {
			gantt.$lightboxControl.fillTabContent(activeId)
		});
	}


	gantt.$lightboxControl = {
		task: {},
		links: {},
		calendars: {},
		resources: {}
	};


	gantt.$lightboxControl.fillTabContent = function (id) {
		id = id || "task"
		gantt.$lightboxControl[id].addForm();
	}
	initTaskEditForm();
	initResourceEditForm();
	initLinkEditForm();
	initCalendarEditForm();

	setTimeout(function () {
		gantt.showLightbox(4)
	}, 200)


</script>
</body>